STEP 1: UNLOAD PACKAGES
library(googlesheets4)
## Warning: package 'googlesheets4' was built under R version 4.2.3
gs4_deauth()
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.2.3
## Warning: package 'ggplot2' was built under R version 4.2.3
## Warning: package 'tibble' was built under R version 4.2.3
## Warning: package 'tidyr' was built under R version 4.2.3
## Warning: package 'readr' was built under R version 4.2.3
## Warning: package 'purrr' was built under R version 4.2.3
## Warning: package 'dplyr' was built under R version 4.2.3
## Warning: package 'stringr' was built under R version 4.2.3
## Warning: package 'forcats' was built under R version 4.2.3
## Warning: package 'lubridate' was built under R version 4.2.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.2     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.2     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.1     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.2.3
library(sf)
## Warning: package 'sf' was built under R version 4.2.3
## Linking to GEOS 3.9.3, GDAL 3.5.2, PROJ 8.2.1; sf_use_s2() is TRUE
library(tigris)
## Warning: package 'tigris' was built under R version 4.2.3
## To enable caching of data, set `options(tigris_use_cache = TRUE)`
## in your R script or .Rprofile.
STEP 2: RETRIEVE GEORGRAPHIC DATA OF THE CITY OF FAIRFAX
## Retrieving data for the year 2021
STEP 3: RETRIEVE BUS STOPS FACILITY DATA
bus.stops <- read_sheet('https://docs.google.com/spreadsheets/d/1OLjEjJJiyjuu5arluv2oiorM4TqzqIk7PQJ9g4Ichvo')
## ✔ Reading from "bus stops".
## ✔ Range 'Sheet1'.
# convert to a map object
pts.bus <- st_as_sf(bus.stops, coords = c("LONGITUDE", "LATITUDE"), crs=default.crs)
STEP 4: RETRIEVE BUS STOPS CRIME DATA; CLEAN, FILTER, AND FORMAT
id.crime <- "1Hdhg5dvPsb28gvkroUU99AKPcGu8rVCp"
crime.full <- read.csv(sprintf("https://docs.google.com/uc?id=%s&export=download", id.crime))

crime.full$date.report <- as.Date(crime.full$date.report)
crime.full$dow <- weekdays(crime.full$date.report)
crime.full$day <- day(crime.full$date.report)
crime.full$month <- substr(crime.full$date.report, 6, 7)
crime <- subset(crime.full, !is.na(crime.full$lat))

crime <- crime %>% filter(date.report > '2020-03-11')

crime.list <- c("SIMPLE ASSAULT","DRUNKENNESS", "VANDALISM", "SHOPLIFTING")

pts.crime <- st_as_sf(crime, coords = c("lon", "lat"), crs=default.crs)
STEP 5: FACILITY STATS AND BUFFERS
facility.mean <- as.numeric(mean(st_length(st_nearest_points(pts.bus, pts.crime))))
facility.sd <- as.numeric(sd(st_length(st_nearest_points(pts.bus, pts.crime))))

facility.buffer <- st_buffer(pts.bus, 75)

leaflet(bus.stops) %>%
  addTiles() %>%
  addMarkers(lng = ~LONGITUDE, lat = ~LATITUDE, 
             clusterOptions = markerClusterOptions()) %>%
  addPolygons(data = facility.buffer)
6
19
20
7
13
4
21
13
facility.activity <- st_join(pts.crime, left = FALSE, facility.buffer["Bus"])
facility.activity <- facility.activity %>% left_join(crime, by = 'ID')
facility.activity <- facility.activity[c(1:24,43)]
names(facility.activity) <- c("number", "date1", "time1", "type", "date2", "time2", "statute", "crime",
                              "crime.description", "statute.description", "date.report", "time.report",
                              "hour1", "hour2", "hour.report", "year", "ID", "dow", "day", "month", "name", 
                              "lat", "lon", "Bus", "geometry")
STEP 6: BEHAVIORIAL ANALYSIS
summary1 <- facility.activity %>%
  group_by(crime.description) %>%
  summarise(count = n()) %>%
  mutate(PCT = round(count/sum(count)*100,2))

summary2 <- facility.activity %>%
  group_by(Bus, crime.description) %>%
  summarise(count = n()) %>%
  mutate(PCT = round(count/sum(count)*100,2))
## `summarise()` has grouped output by 'Bus'. You can override using the `.groups`
## argument.
facility.activity <- subset(facility.activity, 
                            facility.activity$crime.description == 'SIMPLE ASSAULT' |
                              facility.activity$crime.description == 'VANDALISM' |
                             facility.activity$crime.description == 'SHOPLIFTING' |                   
facility.activity$crime.description == 'DRUNKENNESS')

Since COVID-19 (2020-03-11, which was the day the World Health Organization declared it to be a pandemic), approximately 49,000 crimes have been reported around bus routes. Amongst the various crime types, vandalism, shoplifting, simple assault, and drunkenness were the top four counts/percentages from the summary tables. Buffer parameters were adjusted to closely reflect these multiple activities around the approximately 103 bus stops in the City of Fairfax.

Crime descriptions—59 observations within a 75 meter buffer:

Bus and Crime descriptions–out of 287 observations/reports, four bus routes were observed within 75 meter buffers:

1C route (184 reports):

29K route (39 reports):

15M route (29 reports):

29N route (22 reports):

Analyzing the summary data tables, it is interesting that although vandalism by itself has consistently been one of the most reported crimes in the area, around the most concentrated bus stops within a 75 meter buffer, little to no reports were identified. Perhaps if the buffer was adjusted to a smaller size these results would change this narrative, but because four different crime types were being observed together, the buffer size needed to account for these measures accordingly. In addition, when assessing the impact of Zero-Fare Transportation systems that was implemented in response to COVID-19, it seems that there has been a negative unintended result for crimes against property, as well as persons near bus stops.

For the remainder of 2023, I predict that shoplifting, simple assaults, drunkenness, and vandalism will be on a steady rise, and other crimes such as larceny and murder may gradually start to increase due to summary data table observations, and because they are in some ways closely related to one another. However, although these crimes may be on the rise it doesn’t necessarily indicate their reports would occur in a more timely manner, especially since crimes against property are often not reported as timely as more serious crimes against persons.

(*Disclaimer: Due to factors such as buffer size, certain crime types may not be adjusted for or may be duplicating in certain areas. In addition the ‘top 4’ list is solely based on the particular crime types observed. Other crime descriptions may or may not have been in the actual ‘top 4’ list. )

STEP 7: SPATIAL ANALYSIS PART I: INTERACTIVE CLUSTER MAP

Areas that have had a concentration of reported vandalism, simple assault, drunkenness, and shoplifting crimes are typically in the Downtown area of the city of Fairfax — which includes George Mason Boulevard, University Drive, Chain Bridge Road, Main Street, Armstrong Street, and Courthouse Drive, and the Police Department (Blenheim Road), as well as the North and slightly Northeast corner of the city — which includes Fairfax Boulevard, Arlington Boulevard, Old Pickett Road, and Blenheim Road, and the South and Southeast corner of the city — which includes the Fairfax County Court area, Yorktown Court, Mainstreet, and Pickett Road. These areas are mainly alongside or come at an intersection of many of the bus stops that populate the city, and simple assaults are shown to be more dispersed across these areas than other observed crime types, however, shoplifting crimes are more distinct in the areas they have been reported in.

The Northwest areas of the city — which includes Atlanta Street, Blue Coat Drive, Flintlock Road, Jermantown Road, Rock Garden Drive, Plantation Parkway, Bevan Drive, and Orchard Street, appear to be coldspots.

Prediction For the remainder of 2023, I predict that crime occuring around bus stops and the statistics therof will generally stay the same, unless there is an increase of awareness, reporting, and resources to prevent these crimes with the trend and patterns that occur with them.

leaflet(facility.activity) %>%
  addProviderTiles("CartoDB.DarkMatter") %>%
  addMarkers(lng = ~lon, lat = ~lat, 
             popup = paste(
               "Crime Description: ", facility.activity$crime.description, "<br>",
               "Date:", facility.activity$date1), 
             clusterOptions = markerClusterOptions()) %>%
  addPolygons(data = fairfax.city, fillColor = 'clear') %>%
  addPolygons(data = facility.buffer)
## Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
## Need '+proj=longlat +datum=WGS84'
17
82
56
47
39
46
Leaflet | © OpenStreetMap contributors © CARTO
('+proj=longlat +datum=WGS84')
## [1] "+proj=longlat +datum=WGS84"
SPATIAL ANALYSIS PART II: HOTSPOTS MAPS

The hotspots of crime in the city of Fairfax since COVID-19 have been more concentrated around the Downtown and Police Department areas of the city, and almost outline the inner city in a triangular shape, with the longest leg (hypotenuse) being affected the most. The very coldspots of the city that experience little to no criminal activity are in the most north and most south areas which include Atlanta Street, Blue Coat Drive, Flintlock Road, Jermantown Road, Rock Garden Drive, Plantation Parkway, Bevan Drive, and Orchard Street, as well as Beritt Street, Collier Road, Sideburn Road, and Cleveland Street, respectively.

For the remainder of 2023, I predict that the patterns and trends of general crime or specific crime types such as drunkenness, shoplifting, and simple assaults will remain consistent, unless any near future bills or implementations that could either change the seriousness level of crimes in terms of arrests, which may produce unintended consequences or reactions amongst the community. Also, the creation or adoption of any programs that will change the way crimes are reported and addressed by police officers, could alsochnage certian crime rates, but in that case it would be a matter of which types of crimes that would either emerge or decrease, not necessarily the location which is for the most part geographically fixed, including the bus routes.

ggplot() + 
  geom_sf(data = fairfax.city, color = "white") +
  geom_sf(data = fairfax.roads, inherit.aes = FALSE, color = "white", size = .3, alpha = .5) + 
  geom_sf(data = facility.buffer) +
  geom_point(aes(x = lon, y = lat, color = "red"), data = facility.activity, alpha = 0.09, size = 1.5) +  
  theme_classic() + 
  theme(plot.title = element_text(size = 20, hjust=.5), plot.subtitle = element_text(size = 8, hjust=.5, margin=margin(2, 0, 5, 0))) + 
  labs(title = "Fairfax, VA", subtitle = "CRIMES SINCE COVID-19 NEAR BUS STOPS")

#By activity type
ggplot() + 
  geom_sf(data = fairfax.city, color = "white") +
  geom_sf(data = fairfax.roads, inherit.aes = FALSE, color = "white", size = .3, alpha = .5) + 
  geom_sf(data = facility.buffer) +
  geom_point(aes(x = lon, y = lat, color = "red"), data = facility.activity, alpha = 0.05, size = 1.5) +  
  theme_classic() + 
  theme(plot.title = element_text(size = 20, hjust=.5), plot.subtitle = element_text(size = 8, hjust=.5, margin=margin(2, 0, 5, 0))) + 
  labs(title = "Fairfax, VA", subtitle = "CRIMES SINCE COVID-19 NEAR BUS STOPS") +
  facet_wrap(~ crime.description, nrow = 3)

TEMPORAL ANALYSIS: TEMPORAL TOPOLOGIES
activity.day.time <- facility.activity %>%
  group_by(dow, hour2) %>%
  summarise(count = n())
## `summarise()` has grouped output by 'dow'. You can override using the `.groups`
## argument.
activity.day.time <- subset(activity.day.time, !is.na(activity.day.time$hour2))

ggplot(activity.day.time, aes(hour2, dow, fill = count)) +
  geom_tile() +
  labs(x = "Hour of Day", y = "Day of Week", title = "Temporal Topology") +
  scale_fill_gradient(low = "white", high = "red") +
  guides(fill = guide_colourbar(title = "CRIMINAL ACTIVITY BY TIME")) +
  scale_y_discrete(limits = c("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")) +
  scale_x_continuous(breaks = c(0:23))+
  coord_fixed()

# By activity type:
activity.type.day.time <- facility.activity %>%
  group_by(crime.description, dow, hour.report) %>%
  summarise(count = n())
## `summarise()` has grouped output by 'crime.description', 'dow'. You can
## override using the `.groups` argument.
activity.type.day.time <- subset(activity.type.day.time, !is.na(activity.type.day.time$hour.report))

ggplot(activity.type.day.time, aes(hour.report, dow, fill = count)) +
  geom_tile(color = "black", lwd = .5, linetype = 1) + 
  geom_text(aes(label = count), color = "black", size = 2.5) +
  labs(x = "Hour of Day", y = "Day of Week", title = "Temporal Topology") +
  scale_fill_gradient(low = "white", high = "red") +
  guides(fill = guide_colourbar(title = "CRIMINAL ACTIVITY BY TIME")) +
  scale_y_discrete(limits = c("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")) +
  scale_x_continuous(breaks = c(0:23))+
  theme(legend.position = "none") +
  coord_fixed() +
  facet_wrap(~ crime.description, nrow = 10)

When analyzing general criminal activity by day of week and hour of day, hotspot areas include:

When analyzing general criminal activity by day of week and hour of day, coldspot areas include:

When analyzing drunkenness, shoplifting, and simple assaults, hotspot and coldspot areas include:

For drunkenness: Hotspots:

Coldspots:

For shoplifting:

Hotspots:

Coldspots:

For simple assaults

Hotspots

Coldspots

When analyzing the different crime types together, each crime takes their own distinct setting within time and space. Simple assaults are more dispersed across times and days of the week, and likewise the hotspots and coldspots appear more “unevenly” concentrated compared to other crime types. Drunkenness is also dispersed across various times and days of the week, however hotspots and coldspots are a bit more distinct, especially when considering the operating hours of bars and other related activities. Shoplifting activities are shifted towards 9am till the end of the day, which is likely due to factors such as operating hours of businesses, popular store times, increase of persons in proximity of one another, etc.

For the remainder of 2023, I predict these trends and patterns will generally remain consistent considering the size and fixed nature of the city. In addition, unless the Zero-Fare policy ceases or unfavorably changes the conditions of leisure and work-life balance, I further think these crime types wouldn’t drastically change.

When considering the daily shifts that patrol and dispatch work from 0700-1900 and 1900-0700 in rotation, I think there is a direct correlation to the closing or opening of certain businesses that shift the levels or occurrence of crimes against property to crimes against persons, especially around bus stops. Also, if certain crime types such as shoplifting and vandalism continue to increase exponentially, I think drastic measures would have had to be in place, especially because it affects taxpayers money, the community of people that depend on public transportation, and the community as a whole. In addition, although these crime types are generally the highest count or percentage of crime around bus stops in observance of the set buffer, it does not necessarily mean the increase or decrease of one is dependent on another, but I think it is worthwhile to integrate these behavioral, spatial, and temporal findings while officers are pursuing calls for service, patrolling, conducting traffic stops, etc., and for knowing how best to allocate resources, training, and additional/rotational staff if needed, or even discussing whether it is beneficial to dispatch officers when and where coldspots are for better awareness and preparedness needed for when and how to respond to crime after the fact.